package com.doge.walknovel.business.novel

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import androidx.activity.viewModels
import androidx.core.view.isVisible
import androidx.core.view.setPadding
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.doge.wnpro.R
import com.doge.walknovel.analysis.analysisEvent
import com.doge.walknovel.analysis.novel_detail
import com.doge.walknovel.api.model.NovelDetailInfo
import com.doge.walknovel.api.model.NovelInfo
import com.doge.walknovel.api.model.CommentInfo
import com.doge.walknovel.business.novel.chapter.NovelChapterActivity
import com.doge.walknovel.business.novel.rating.RatingCommentNovelDialogFragment
import com.doge.walknovel.business.novel.rating.RatingCommentNovelDialogFragment.Companion.TYPE_COMMENTS
import com.doge.walknovel.business.novel.rating.RatingCommentNovelDialogFragment.Companion.TYPE_NOVEL
import com.doge.walknovel.business.novel.reply.ReplyDialogFragment
import com.doge.walknovel.business.home.library.LibraryRepository
import com.doge.walknovel.business.reader.ChapterCacheHelper
import com.doge.walknovel.business.reader.ReaderActivity
import com.doge.walknovel.business.reader.download.ChapterTextCacheHelper
import com.doge.walknovel.core.BaseActivity
import com.doge.walknovel.core.account.AccountHelper
import com.doge.walknovel.core.base.LoadStatus
import com.doge.walknovel.core.base.adapters.RecyclerDataAdapterObserver
import com.doge.walknovel.core.base.isRefreshing
import com.doge.wnpro.databinding.ActivityNovelDetailBinding
import com.doge.walknovel.utils.*

class NovelDetailActivity : BaseActivity() {
    private val binding by lazy { ActivityNovelDetailBinding.inflate(layoutInflater) }
    private val referId: Int? by lazy { intent?.getIntExtra(NovelRefer.EXTRA_REFER_ID, 0) }
    private val refer by lazy { intent?.getStringExtra(NovelRefer.EXTRA_REFER)!! }
    private val novelId by lazy { intent?.getIntExtra(EXTRA_NOVEL_ID, 0)!! }
    private val viewModel: NovelDetailViewModel by viewModels { NovelDetailViewModelFactory(novelId, refer, referId) }
    private val bottoms by lazy { arrayOf(binding.bottom, binding.readCard, binding.shadow, binding.add) }
    private val adapter by lazy { NovelDetailAdapter() }
    private val layoutManager by lazy { LinearLayoutManager(binding.recyclerView.context) }
    private var viewDataAdapterObserver: RecyclerDataAdapterObserver? = null
    private var bookDetail: NovelDetailInfo? = null
    private var chapterPreloaded = false
    private var pageTitleDisplayed = false
    private var pageTitleAnimating = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        analysisEvent(novel_detail)
        setContentView(binding.root)
        systemWindowInsetsTop.observe(this) {
            binding.fitsSys.setPadding(it / 2)
        }
        bottoms.forEach { it.isVisible = false }

        binding.back.setOnClickCallback { onBackPressed() }
        binding.read.setOnClickCallback {
            ReaderActivity.start(this, novelId, bookDetail?.readerChapterId, refer, referId)
        }
        binding.add.setOnClickCallback {
            AccountHelper.requiredLogin {
                if (binding.add.tag != true) {
                    LibraryRepository.get().requestAddNovel(NovelInfo.form(bookDetail))
                } else {
                    toast(R.string.already_added_to_the_bookshelf)
                }
            }
        }
        updateAddBtn()
        binding.refreshLayout.setColorSchemeResources(R.color.pull_refresh)
        binding.refreshLayout.setOnRefreshListener {
            viewModel.requestNovelInfo()
            viewModel.requestNovelComments()
        }
        binding.recyclerView.itemAnimator = null
        binding.recyclerView.layoutManager = layoutManager
        binding.recyclerView.adapter = adapter
        viewDataAdapterObserver = RecyclerDataAdapterObserver(binding.recyclerView).also {
            adapter.registerAdapterDataObserver(it)
        }
        adapter.setListener(::handleAdapterCallback)
        binding.recyclerView.addOnScrollListener(scrollListener)

        LibraryRepository.get().adding.observe(this) {
            binding.addLoading.isVisible = it.isRefreshing()
            updateAddBtn()
        }

        viewModel.bookDetail.observe(this) {
            bookDetail = it
            preloadNovelChapterInfo(it)
            updateNovelInfoLoaded()
        }
        viewModel.loading.observe(this) {
            binding.refreshLayout.isRefreshing = it.isRefreshing() && !binding.initLoading.isVisible
        }
        viewModel.dataList.observe(this) {
            val hasNovelInfo = it.any { it.id == NovelDetailState.ID_INFO }
            if (hasNovelInfo) updateNovelInfoLoaded()
            adapter.submitList(it)
        }
        viewModel.createLoading.observe(this) {
            if (it == LoadStatus.SUCCESS) {
                scrollToSelfNewComments()
            }
        }
        viewModel.requestNovelInfo()
        viewModel.requestNovelComments()
    }

    private fun handleAdapterCallback(action: String, item: Any?) {
        when (action) {
            CHAPTERS -> NovelChapterActivity.start(this, item as? NovelDetailInfo?, refer, referId)
            MIGHT_LIKE -> start(this, (item as? NovelInfo?)?.novelId, NovelRefer.novelDetailMightLike, (item as? NovelInfo?)?.novelId)
            RATING, COMMENTS_INPUT -> {
                AccountHelper.requiredLogin {
                    RatingCommentNovelDialogFragment.newInstance(
                        TYPE_NOVEL, novelId, null, null, null,
                        refer, referId
                    )
                        .show(supportFragmentManager)
                }
            }
            COMMENTS_REPLY -> {
                AccountHelper.requiredLogin {
                    RatingCommentNovelDialogFragment.newInstance(
                        TYPE_COMMENTS,
                        novelId,
                        (item as? CommentInfo?)?.commentId, null, null,
                        refer, referId
                    )
                        .show(supportFragmentManager)
                }
            }
            COMMENTS_COLLECT -> {
                AccountHelper.requiredLogin {
                    viewModel.requestCollectComments(item as? CommentInfo?)
                }
            }
            COMMENTS_MORE -> {
                AccountHelper.requiredLogin {
                    (item as? CommentInfo?)?.commentId?.let {
                        ReplyDialogFragment.newInstance(it).show(supportFragmentManager)
                    }
                }
            }
        }
    }

    private fun updateAddBtn() {
        val isAdded = LibraryRepository.get().containsNovel(novelId)
        binding.add.setImageResource(if (isAdded) R.mipmap.novel_detail_added else R.mipmap.novel_detail_add)
        binding.add.tag = isAdded
    }

    private fun updateNovelInfoLoaded() {
        binding.pageTitle.text = bookDetail?.title
        bottoms.forEach { it.isVisible = true }
        if (binding.initLoading.visibility == View.VISIBLE) binding.back.setImageResource(R.mipmap.nav_back_white)
        binding.initLoading.isVisible = false
    }

    private fun preloadNovelChapterInfo(data: NovelDetailInfo?) {
        if (data == null) return
        if (!chapterPreloaded) {
            chapterPreloaded = true
            ChapterCacheHelper.requireChapterInfo(data.readerChapterId) {
                ChapterTextCacheHelper.requireChapterText(novelId, it) // load to memory from disk
            }
        }
    }

    private val scrollListener = object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            if (RecyclerView.SCROLL_STATE_IDLE == newState) {
                notifyTopTitleChanged()
            }
        }
    }

    private fun notifyTopTitleChanged() {
        log("notifyTopTitleChanged $pageTitleAnimating")
        if (pageTitleAnimating) return
        val isTop = adapter.slideInTop()
        if (pageTitleDisplayed && isTop) {
            hidePageTitleAnimation()
        } else if (!pageTitleDisplayed && !isTop) {
            displayPageTitleAnimation()
        }
    }

    private fun displayPageTitleAnimation() {
        pageTitleAnimating = true
        pageTitleDisplayed = true
        useTranslucentStatusBar(true)
        binding.back.setImageResource(if (pageTitleDisplayed) R.mipmap.nav_back else R.mipmap.nav_back_white)
        binding.pageBg.animate().alpha(1f).setListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                pageTitleAnimating = false
            }
        }).start()
        binding.pageShadow.animate().alpha(1f).start()
        binding.pageTopStatus.animate().alpha(1f).start()
        binding.pageTitle.animate().alpha(1f).start()
    }

    private fun hidePageTitleAnimation() {
        pageTitleAnimating = true
        pageTitleDisplayed = false
        useTranslucentStatusBar(false)
        binding.back.setImageResource(if (pageTitleDisplayed) R.mipmap.nav_back else R.mipmap.nav_back_white)
        binding.pageBg.animate().alpha(0f).setListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                pageTitleAnimating = false
            }
        }).start()
        binding.pageShadow.animate().alpha(0f).start()
        binding.pageTopStatus.animate().alpha(0f).start()
        binding.pageTitle.animate().alpha(0f).start()
    }

    private fun scrollToSelfNewComments() {
        binding.recyclerView.alpha = 0f
        binding.recyclerView.translationY = 80.dp.toFloat()
        binding.recyclerView.animate().alpha(1f)
            .translationY(0f)
            .setInterpolator(DecelerateInterpolator(2f))
            .setStartDelay(200)
            .setDuration(150).start()
        binding.recyclerView.postDelayed({
            layoutManager.scrollToPositionWithOffset(
                2,
                44.dp + (systemWindowInsetsTop.value ?: 0)
            )
        }, 200)
    }

    companion object {
        private const val EXTRA_NOVEL_ID = "novelId"
        fun start(context: Context?, novelId: Int?, refer: String, referId: Int? = null) {
            if (context == null || novelId == null) return
            context.startActivity(Intent(context, NovelDetailActivity::class.java).apply {
                if (context == appContext) flags = Intent.FLAG_ACTIVITY_NEW_TASK
                putExtra(EXTRA_NOVEL_ID, novelId)
                putExtra(NovelRefer.EXTRA_REFER, refer)
                referId?.let { putExtra(NovelRefer.EXTRA_REFER_ID, it) }
            })
        }
    }
}